using SmartCommunity.Models;
using Mapster;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Caching.Memory;

namespace SmartCommunity.WebApi.Services.System
{
    /// <summary>
    /// 服务类：参数配置
    /// </summary>
    public class ConfigService : BaseService<ConfigEntity>
    {
        #region 构造函数
        protected readonly SCDBContext ctx;
        private readonly IMemoryCache cache;

        public ConfigService(SCDBContext ctx, IMemoryCache cache)
        {
            this.ctx = ctx;
            this.cache = cache;
        }
        #endregion

        #region 数据查询 
        /// <summary>
        /// 分页查询
        /// </summary>
        public async Task<PageResult<ConfigDto>> FindPagedList(ConfigQuery configQuery, Pager pager, LoginUser user)
        {
            var query = ctx.Configs.AsNoTracking().Where(configQuery.GetQueryExpression());
            var data = await FindPagedList(query, pager, o => o.OrderByDescending(t => t.CreatedTime));
            return data.Map(o => o.Adapt<ConfigDto>());
        }

        /// <summary>
        /// 根据参数配置ID查询
        /// </summary>
        public async Task<ConfigDto> FindConfigById(int configId)
        {
            var entity = await FindById(configId);
            return entity.Adapt<ConfigDto>();
        }

        /// <summary>
        /// 根据ID查询实体类
        /// </summary>
        private async Task<ConfigEntity> FindById(int id)
        {
            return await ctx.Configs.SingleOrDefaultAsync(a => a.ConfigId == id)
                ?? throw new NotFoundException($"找不到指定的参数配置,Id:{id}");
        }
        #endregion

        #region 增 删 改
        /// <summary>
        /// 新增参数配置
        /// </summary>
        public async Task<ConfigDto> CreateConfig(ConfigDto dto, LoginUser user)
        {
            // 新建对象
            var entity = new ConfigEntity();
            // 复制属性
            await CopyDtoToEntity(dto, entity, user, true);
            // 执行保存
            ctx.Configs.Add(entity);
            await ctx.SaveChangesAsync();
            // 清除缓存
            RemoveCache(entity.ConfigKey);
            // 返回Dto
            return entity.Adapt<ConfigDto>();
        }

        /// <summary>
        /// 更新参数配置
        /// </summary>
        public async Task UpdateConfig(ConfigDto dto, LoginUser user)
        {
            // 原始数据
            var entity = await FindById(dto.ConfigId);
            // 更新字段
            await CopyDtoToEntity(dto, entity, user, false);
            // 执行更新
            await ctx.SaveChangesAsync();
            // 清除缓存
            RemoveCache(entity.ConfigKey);
        }

        /// <summary>
        /// 复制dto属性到实体字段
        /// </summary>
        private async Task CopyDtoToEntity(ConfigDto dto, ConfigEntity entity, LoginUser user, bool isNew)
        {
            // 检查数据重复
            if (await ctx.Configs.AnyAsync(a => a.ConfigId != dto.ConfigId && (a.ConfigName == dto.ConfigName || a.ConfigKey == dto.ConfigKey)))
            {
                throw new MessageException("当前已存在相同名称或编码的参数配置");
            }
            entity.ConfigName = dto.ConfigName;
            entity.ConfigKey = dto.ConfigKey;
            entity.ConfigValue = dto.ConfigValue;
            entity.ExtField = dto.ExtField;
            entity.Remark = dto.Remark;

            // 记录操作人
            if (isNew)
            {
                entity.CreatedBy = user.Username;
                entity.CreatedTime = DateTime.Now;
            }
            entity.UpdatedBy = user.Username;
            entity.UpdatedTime = DateTime.Now;
        }

        /// <summary>
        /// 根据ID删除参数配置
        /// </summary>
        public async Task DeleteByIds(IEnumerable<int> ids, LoginUser user)
        {
            var configs = await ctx.Configs.Where(a => ids.Contains(a.ConfigId)).ToListAsync();
            if (configs.Count != ids.Count())
            {
                throw new MessageException("查询出的数据和传入的ID不匹配，请刷新后再试。");
            }
            // 判断是否能删除
            foreach (var entity in configs)
            {
                // 清除缓存
                RemoveCache(entity.ConfigKey);
                ctx.Configs.Remove(entity);
            }
            // 提交事务
            await ctx.SaveChangesAsync();
        }
        #endregion

        public async Task<ConfigDto?> GetConfigByKey(string key)
        {
            return await cache.GetOrCreateAsync(AppConstants.CACHE_PREFIX_CONFIG + key, async o =>
             {
                 o.SlidingExpiration = TimeSpan.FromHours(4);
                 var cfg = await ctx.Configs.SingleOrDefaultAsync(a => a.ConfigKey == key);
                 return cfg?.Adapt<ConfigDto>();
             });
        }

        public async Task<string> GetConfigValue(string key, string defaultVal = "")
        {
            var dto = await GetConfigByKey(key);
            return null == dto ? defaultVal : dto.ConfigValue;
        }

        private void RemoveCache(string key)
        {
            cache.Remove(AppConstants.CACHE_PREFIX_CONFIG + key);
        }
    }
}
